home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevstc4.c < prev    next >
C/C++ Source or Header  |  1996-05-09  |  8KB  |  302 lines

  1. /* Copyright (C) 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevstc4.c */
  20. /* Epson Stylus-Color Printer-Driver */
  21.  
  22. /***
  23.      This file holds a byte-Implementation of the Floyd-Steinberg error
  24.      diffusion-algorithm. This algorithm is an alternative for high quality 
  25.      printing in conjunction with the PostScript-Header stcolor.ps:
  26.  
  27.           gs -sDEVICE=stcolor -sDithering=fs2 <other options> stcolor.ps ...
  28.  
  29.      THIS ALGORIHM WAS WRITTEN BY STEVEN SINGER (S.Singer@ph.surrey.ac.uk)
  30.      AS PART OF escp2cfs2. 
  31.      THIS IMPLEMENTATION INCORPORATES ONLY FEW CHANGES TO THE ORIGINAL CODE.
  32.  
  33.  ***/
  34.  
  35. #include "gdevstc.h"
  36.  
  37. /*
  38.  * escp2c_pick best scans for best matching color 
  39.  */
  40. private byte *
  41. escp2c_pick_best(byte *col)
  42. {
  43.     static byte colour[8][3] = {
  44.        {  0,  0,  0},{255,  0,  0},{  0,255,  0},{255,255,  0},
  45.        {  0,  0,255},{255,  0,255},{  0,255,255},{255,255,255}};
  46.     register int x, y, z, dx, dy, dz, dz2, dx2, dx3, dx4;
  47.     register byte *p;
  48.     register long md, d;
  49.  
  50.     md = 16777216; /* plenty */
  51.  
  52. /*
  53.    Note that I don't use a simple distance algorithm. That can lead to a block
  54.    of (130,127,127) being dithered as red-cyan. This algorithm should make
  55.    it use black-white-red. This is very important, as a coloured block in
  56.    the middle of a grey block can, via error diffusion, perturb the
  57.    surrounding colours sufficiently for this to happen.
  58. */
  59.  
  60. /*
  61.    The next bit is equivalent to this, but faster.
  62.  
  63.     x = col[0];
  64.     y = col[1];
  65.     z = col[2];
  66.     for(n=8; n--; )
  67.     {
  68.     dx = x - colour[n][0];
  69.     dy = y - colour[n][1];
  70.     dz = z - colour[n][2];
  71.     d = dx*(dx-(dy>>1)) + dy*(dy-(dz>>1)) + dz*(dz-(dx>>1));
  72.     if (d < md)
  73.     {
  74.         md = d;
  75.         p = n;
  76.     }
  77.     }
  78. */
  79.  
  80. /*
  81.  * Test colours in gray code order to reduce number of recalculations.
  82.  * I bet you can't find an optimiser that would do this automatically.
  83.  */
  84.  
  85.     x = col[0];
  86.     y = col[1];
  87.     z = col[2];
  88.     dx = x*(x-(y>>1));
  89.     dy = y*(y-(z>>1));
  90.     dz = z*(z-(x>>1));
  91.     md = dx + dy + dz;
  92.     p = colour[0];
  93.     x -= 255;
  94.     dx2 = x*(x-(y>>1));
  95.     dz2 = z*(z-(x>>1));
  96.     if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[1];}
  97.     y -= 255;
  98.     dx3 = x*(x-(y>>1));
  99.     dy = y*(y-(z>>1));
  100.     if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[3];}
  101.     x += 255;
  102.     dx4 = x*(x-(y>>1));
  103.     if ((d = dx4 + dy + dz) < md) {md = d; p = colour[2];}
  104.     z -= 255;
  105.     dy = y*(y-(z>>1));
  106.     dz = z*(z-(x>>1));
  107.     if ((d = dx4 + dy + dz) < md) {md = d; p = colour[6];}
  108.     x -= 255;
  109.     dz2 = z*(z-(x>>1));
  110.     if ((d = dx3 + dy + dz2) < md) {md = d; p = colour[7];}
  111.     y += 255;
  112.     dy = y*(y-(z>>1));
  113.     if ((d = dx2 + dy + dz2) < md) {md = d; p = colour[5];}
  114.     if ((d = dx + dy + dz) < md) {p = colour[4];}
  115.     return(p);
  116. }
  117.  
  118. /*
  119.  * escp2c_conv_stc converts into the ouput format used by stcolor
  120.  */
  121. private void
  122. escp2c_conv_stc(byte *p, byte *q, int i)
  123. {
  124.     for(; i; p+=3, i-=3)
  125.         *q++ = (*p & RED) | (p[1] & GREEN) | (p[2] & BLUE);
  126. }
  127.  
  128.  
  129. /*
  130.  * Limit byte-values
  131.  */
  132. #define LIMIT(a) if (a > 255) a = 255; if (a < 0) a = 0
  133. #define LIMIT2(a) if (a > 127) a = 127; if (a < -128) a = -128; \
  134.                 if (a < 0) a += 256
  135. /*
  136.  * Main routine of the algorithm
  137.  */
  138. int 
  139. stc_fs2(stcolor_device *sd,int npixel,byte *in,byte *buf,byte *out)
  140. {
  141.    int fullcolor_line_size = npixel*3;
  142.  
  143. /* ============================================================= */
  144.    if(npixel > 0) {  /* npixel >  0 -> scanline-processing       */
  145. /* ============================================================= */
  146.  
  147. /*    -------------------------------------------------------------------- */
  148.       if(in == NULL) { /* clear the error-buffer upon white-lines */
  149. /*    -------------------------------------------------------------------- */
  150.  
  151.          memset(buf,0,fullcolor_line_size);
  152.  
  153. /*    ------------------------------------------------------------------- */
  154.       } else {                 /* do the actual dithering                 */
  155. /*    ------------------------------------------------------------------- */
  156.     int i, j, k, e, l, i2, below[3][3], *fb, *b, *bb, *tb;
  157.     byte *p, *q, *cp;
  158.     static int dir = 1;
  159.  
  160.     p = buf;
  161.     if (*p != 0 || memcmp((char *) p, (char *) p + 1, fullcolor_line_size - 1))
  162.     {
  163.     for(p = in, q=buf, i=fullcolor_line_size;
  164.         i--; p++, q++ )
  165.     {
  166.         j = *p + ((*q & 128) ? *q - 256 : *q);
  167.         LIMIT(j);
  168.         *p = j;
  169.     }
  170.     }
  171.  
  172.     p = in;
  173.  
  174.     fb = below[2];
  175.     b = below[1];
  176.     bb = below[0];
  177.     *b = b[1] = b[2] = *bb = bb[1] = bb[2] = 0;
  178.  
  179.     if (dir)
  180.     {
  181.         for(p = in, q=buf-3,
  182.         i=fullcolor_line_size; i; i-=3)
  183.         {
  184.         cp = escp2c_pick_best(p);
  185.         for(i2=3; i2--; p++, q++, fb++, b++, bb++)
  186.         {
  187.             j = *p;
  188.             *p = *cp++;
  189.             j -= *p;
  190.             if (j != 0)
  191.             {
  192.             l = (e = (j>>1)) - (*fb = (j>>4));
  193.             if (i > 2)
  194.             {
  195.                 k = p[3] + l;
  196.                 LIMIT(k);
  197.                 p[3] = k;
  198.             }
  199.             *b += e - (l = (j>>2) - *fb);
  200.             if (i < fullcolor_line_size)
  201.             {
  202.                 l += *bb;
  203.                 LIMIT2(l);
  204.                 *q = l;
  205.             }
  206.             }
  207.             else
  208.             *fb = 0;
  209.         }
  210.         tb = bb-3;
  211.         bb = b-3;
  212.         b = fb-3;
  213.         fb = tb;
  214.         }
  215.         *q = *bb;
  216.         q[1] = bb[1];
  217.         q[2] = bb[2];
  218.         dir = 0;
  219.     }
  220.     else
  221.     {
  222.         for(p = in+fullcolor_line_size-1,
  223.         q = buf+fullcolor_line_size+2, i=fullcolor_line_size; 
  224.                 i; i-=3)
  225.         {
  226.         cp = escp2c_pick_best(p-2) + 2;
  227.         for(i2=3; i2--; p--, q--, fb++, b++, bb++)
  228.         {
  229.             j = *p;
  230.             *p = *cp--;
  231.             j -= *p;
  232.             if (j != 0)
  233.             {
  234.             l = (e = (j>>1)) - (*fb = (j>>4));
  235.             if (i > 2)
  236.             {
  237.                 k = p[-3] + l;
  238.                 LIMIT(k);
  239.                 p[-3] = k;
  240.             }
  241.             *b += e - (l = (j>>2) - *fb);
  242.             if (i < fullcolor_line_size)
  243.             {
  244.                 l += *bb;
  245.                 LIMIT2(l);
  246.                 *q = l;
  247.             }
  248.             }
  249.             else
  250.             *fb = 0;
  251.         }
  252.         tb = bb-3;
  253.         bb = b-3;
  254.         b = fb-3;
  255.         fb = tb;
  256.         }
  257.         *q = *bb;
  258.         q[1] = bb[1];
  259.         q[2] = bb[2];
  260.         dir = 1;
  261.     }
  262.     
  263.     escp2c_conv_stc(in, out, fullcolor_line_size);
  264.  
  265. /*    ------------------------------------------------------------------- */
  266.       }                        /* buffer-reset | dithering                */
  267. /*    ------------------------------------------------------------------- */
  268.  
  269.  
  270. /* ============================================================= */
  271.    } else {          /* npixel <= 0 -> initialisation            */
  272. /* ============================================================= */
  273.  
  274.  
  275. /*
  276.  * check wether the number of components is valid
  277.  */
  278.       if(sd->color_info.num_components != 3)                       return -1;
  279.  
  280. /*
  281.  * check wether stcdither & TYPE are correct
  282.  */
  283.       if(( sd->stc.dither                    == NULL) ||
  284.          ((sd->stc.dither->flags & STC_TYPE) != STC_BYTE))         return -2;
  285.  
  286. /*
  287.  * check wether the buffer-size is sufficiently large
  288.  */
  289.       if((sd->stc.dither->flags/STC_SCAN) < 1)                     return -3;
  290.  
  291. /*
  292.  * finally clear the buffer
  293.  */
  294.       memset(buf,0,-fullcolor_line_size);
  295.  
  296. /* ============================================================= */
  297.    } /* scanline-processing or initialisation */
  298. /* ============================================================= */
  299.  
  300.    return 0;
  301. }
  302.